package com.unknow.first.dapp.admin.account.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.unknow.first.dapp.admin.account.constants.AccountConstants;
import com.unknow.first.dapp.admin.account.constants.AccountConstants.TradeType;
import com.unknow.first.dapp.admin.account.constants.AccountConstants.TradeRemarkColumn;
import com.unknow.first.dapp.admin.account.mapper.AddressAccountInfo;
import com.unknow.first.dapp.admin.account.mapper.AddressCoinConfig;
import com.unknow.first.dapp.admin.account.mapper.AddressTransfer;
import com.unknow.first.dapp.admin.account.mapper.AddressTransferMapper;
import com.unknow.first.dapp.admin.account.service.AddressAccountInfoService;
import com.unknow.first.dapp.admin.account.service.AddressCoinConfigService;
import com.unknow.first.dapp.admin.account.service.AddressTransferService;
import com.unknow.first.dapp.admin.account.utils.Web3Utils;
import org.cloud.vo.ResponseResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import java.math.BigDecimal;
import java.util.Locale;

@Service
public class AddressTransferServiceImpl extends ServiceImpl<AddressTransferMapper, AddressTransfer> implements AddressTransferService {

    @Autowired
    private AddressAccountInfoService addressAccountInfoService;
    @Autowired
    private AddressCoinConfigService addressCoinConfigService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResponseResult<?> transfer(Integer coinId, String from, String to, BigDecimal amount, String remark) throws Exception {
        from = from.toLowerCase(Locale.ROOT);
        to = to.toLowerCase(Locale.ROOT);
        Assert.isTrue(Web3Utils.single().isETHValidAddress(to), "account.error.transfer.faultETHAddress");
        Assert.isTrue(amount != null && amount.compareTo(BigDecimal.ZERO) > 0, "account.error.transfer.amountTooSmall");
        Assert.isTrue(!from.equalsIgnoreCase(to), "account.error.transfer.noGiveYourself");
        AddressCoinConfig coinConfig = addressCoinConfigService.getById(coinId);
        Assert.isTrue(coinConfig != null && coinConfig.getStatus() != AccountConstants.CoinConfigStatus.FORBIDDEN.status
                && coinConfig.getTransferStatus() == AccountConstants.CoinConfigTransferStatus.NORMAL.status,
            "account.error.transfer.coinTransferClose");
        AddressAccountInfo account = addressAccountInfoService.getAddressAccountByCoinId(from, coinId);
        Assert.isTrue(account != null && account.getBalance().compareTo(amount) >= 0, "account.error.transfer.notSufficientFunds");
        Assert.isTrue(account.getStatus() == AccountConstants.AccountStatus.NORMAL.status, "account.error.accountForbidden");
        BigDecimal fromPayAmount = BigDecimal.ZERO.subtract(amount);

        AddressTransfer transfer = new AddressTransfer();
        transfer.setFromAddress(from);
        transfer.setToAddress(to);
        transfer.setCoinId(coinId);
        transfer.setCoinName(coinConfig.getCoinName());
        transfer.setCoinSymbol(coinConfig.getCoinSymbol());
        transfer.setAmount(amount);
        transfer.setRemark(remark);
        transfer.setFeeAmount(BigDecimal.ZERO);
        transfer.setCreatedBy(from);
        transfer.setUpdatedBy(from);
        Assert.isTrue(getBaseMapper().insert(transfer) > 0, "system.error.noDataUpdated");

        JSONObject jsonObject = new JSONObject();
        jsonObject.put(TradeRemarkColumn.PAY_TO.code, to);

        addressAccountInfoService.processFundAndDetail(fromPayAmount, coinConfig, TradeType.TRANSFER,
            jsonObject.toJSONString(), transfer.getId(), from, "System");

        jsonObject = new JSONObject();
        jsonObject.put(TradeRemarkColumn.PAY_BY.code, from);
        addressAccountInfoService.processFundAndDetail(amount, coinConfig, TradeType.TRANSFER, jsonObject.toJSONString(),
            transfer.getId(), to, "System");
        return ResponseResult.createSuccessResult();
    }
}
